﻿function Numeric(thousandsSeparator, decimalSeparator, currencySymbol, defaultValue)
{
    Numeric.DecimalSeparator    = decimalSeparator,
    Numeric.ThousandsSeparator  = thousandsSeparator,
    Numeric.CurrencySymbol      = currencySymbol,
    Numeric.DefaultValue        = defaultValue,
    Numeric.ParseSettings       = function (thousandsSeparator, decimalSeparator, currencySymbol, defaultValue)
    {
        var settings = { ThousandsSeparator: thousandsSeparator, DecimalSeparator: decimalSeparator, CurrencySymbol: currencySymbol, DefaultValue: defaultValue };
        
        if (settings.ThousandsSeparator == null || settings.ThousandsSeparator == undefined)
            settings.ThousandsSeparator = Numeric.ThousandsSeparator;

        if (settings.DecimalSeparator == null || settings.DecimalSeparator == undefined)
            settings.DecimalSeparator = Numeric.DecimalSeparator;

        if (settings.CurrencySymbol == null || settings.CurrencySymbol == undefined)
            settings.CurrencySymbol = Numeric.CurrencySymbol;

        if (settings.DefaultValue == null || settings.DefaultValue == undefined)
            settings.DefaultValue = Numeric.DefaultValue;

        return settings;
    };
    return {
        Validation:
        {
            isNumber: function(value) {
                return !isNaN(value);
            }
        },
        Conversion:
        {
            Parent: null,
            toNumber: function (value, thousandsSeparator, decimalSeparator, currencySymbol)
            {
                /*
                    This function expects a string value, and based on given decimal separator and thousands separator,
                    formats it to US standard format and parses it as Float.
                */
                this.Parent = new Numeric(Numeric.ThousandsSeparator, Numeric.DecimalSeparator, Numeric.CurrencySymbol, Numeric.DefaultValue);

                var settings = Numeric.ParseSettings(thousandsSeparator, decimalSeparator, currencySymbol);

                value = value + "";
                value = value.replace(settings.CurrencySymbol, "");
                if (value.length == 0)
                    return 0;

                var US_Formatted_Value = value + "";
                if (!this.Parent.Formatting.validateFormat(value, ',', '.'))
                {
                    US_Formatted_Value = US_Formatted_Value.replace(settings.DecimalSeparator, '*');
                    US_Formatted_Value = US_Formatted_Value.replace(settings.ThousandsSeparator, settings.DecimalSeparator);
                    US_Formatted_Value = US_Formatted_Value.replace('*', settings.ThousandsSeparator);
                }
                US_Formatted_Value = US_Formatted_Value.replace(',', ""); //parseFloat function requires only decimal separator

                return parseFloat(US_Formatted_Value);
            }
        },
        Formatting:
        {
            Parent: null,
            validateFormat: function (value, thousandsSeparator, decimalSeparator, currencySymbol)
            {
                this.Parent = new Numeric(Numeric.ThousandsSeparator, Numeric.DecimalSeparator, Numeric.CurrencySymbol, Numeric.DefaultValue);
                var settings = Numeric.ParseSettings(thousandsSeparator, decimalSeparator, currencySymbol);
                /* Accepts:
                    + Any number with or without decimals
                    + Any of the above, with or without thousands separator
                    + Any of above, preceding with currency symbol
                */
                //var expression = /^(\$|)([1-9]\d{0,2}(\.\d{3})*|([1-9]\d*))(\,\d{1,})?$/;
                var expression = '^(\\' + settings.CurrencySymbol + '|)([1-9]\\d{0,2}(\\' + settings.ThousandsSeparator + '\\d{3})*|([1-9]\\d*))(\\' + settings.DecimalSeparator + '\\d{1,})?$';
                var regEx = new RegExp(expression, "gmi");
                var matches = (value + "").match(regEx);
                if ( matches != null && matches[0] == value )
                    return true;
                else
                    return false;
            },
            formatCurrency: function (number, currencySymbol, decimalPlaces, decimalSeparator, thousandsSeparator) {
                this.Parent = new Numeric(Numeric.ThousandsSeparator, Numeric.DecimalSeparator, Numeric.CurrencySymbol, Numeric.DefaultValue);
                var formattedNumber = this.Parent.Formatting.format(number, decimalPlaces, decimalSeparator, thousandsSeparator);
                if (currencySymbol == null || currencySymbol == undefined)
                    currencySymbol = Numeric.CurrencySymbol;
                return currencySymbol + " " + formattedNumber;
            },
            format: function (number, decimalPlaces, decimalSeparator, thousandsSeparator, defaultValue) {
                /*
                    This function expects a number object with US format, and formats it with given parameters
                */
                this.Parent = new Numeric(Numeric.ThousandsSeparator, Numeric.DecimalSeparator, Numeric.CurrencySymbol, Numeric.DefaultValue);
                
                var settings = Numeric.ParseSettings(thousandsSeparator, decimalSeparator, currencySymbol, defaultValue);

                if ( typeof number != 'number' )
                    number = this.Parent.Conversion.toNumber(number, settings.DecimalSeparator, settings.ThousandsSeparator);
                else
                    number = parseFloat(number);

                if ( isNaN(number) )
                    return this.Parent.Formatting.format(settings.DefaultValue, decimalPlaces, settings.DecimalSeparator, settings.ThousandsSeparator, settings.DefaultValue);

                //Rounding..
                if (decimalPlaces == null || decimalPlaces == undefined)
                    decimalPlaces = 2;
                number = number.toFixed(decimalPlaces);

                //Take "." as decimal separator
                number = number.toString().replace(".", settings.DecimalSeparator !== undefined ? settings.DecimalSeparator : ",");

                //Thousands separator.
                if (settings.ThousandsSeparator)
                {
                    var thousands = new RegExp("(-?[0-9]+)([0-9]{3})");
                    while (thousands.test(number))
                    {
                        number = number.replace(thousands, "$1" + settings.ThousandsSeparator + "$2");
                    }
                }

                return number;
            }
        }
    }
}